package com.example.mybatis.flex.type;

import com.denodo.vdb.jdbcdriver.VDBJDBCResultSetMetaData;
import com.denodo.vdb.jdbcdriver.printer.Field;
import com.denodo.vdb.vdbinterface.common.clientResult.vo.descriptions.type.RegisterVO;
import com.denodo.vdb.vdbinterface.common.clientResult.vo.descriptions.type.RegisterValueVO;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DenodoCompoundTypeHandler extends BaseTypeHandler {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
        ps.setObject(i, parameter);
    }

    @Override
    public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return compoundValue(rs, rs.findColumn(columnName));
    }

    @Override
    public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return compoundValue(rs, columnIndex);
    }

    @Override
    public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return compoundValue(cs.getResultSet(), columnIndex);
    }

    private Object compoundValue(ResultSet rs, int columnIndex) throws SQLException {
        VDBJDBCResultSetMetaData md = (VDBJDBCResultSetMetaData) rs.getMetaData();
        int filedType = md.getColumnType(columnIndex);
        Object filedValue = rs.getObject(columnIndex);
        if (filedValue != null) {
            // The JDBC API represents the values of type 'register' as 'Struct' objects.
            if (filedType == Types.STRUCT) {
                Map map = getMap(columnIndex, md, filedValue);
                return map;
            }
            // The JDBC API represents the values of type 'array' as 'Array' objects.
            // 'Array' is an array of 'Struct' objects.
            else if (filedType == Types.ARRAY) {
                Object[] registers = (Object[]) rs.getArray(columnIndex).getArray();
                List list = new ArrayList();
                for (Object register : registers) {
                    list.add(getMap(columnIndex, md, register));
                }
            }
        }
        return null;
    }

    private Map getMap(int columnIndex, VDBJDBCResultSetMetaData md, Object filedValue) throws SQLException {
        Field field = md.getFields()[columnIndex - 1];
        RegisterVO vdpType = ((RegisterVO) field.getVdpType());
        List<RegisterValueVO> registerSubTypes = vdpType.getElements();
        Struct struct = (Struct) filedValue;
        Object[] structValues = struct.getAttributes();
        Map map = new HashMap();
        for (int i = 0; i < registerSubTypes.size(); i++) {
            String subFieldName = registerSubTypes.get(i).getName();
            Object subFieldValue = structValues[i];
            if (subFieldValue != null) {
                map.put(subFieldName, subFieldValue);
            }
        }
        return map;
    }
}
